﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
using System.Collections;
namespace MSBIHelper.Helper
{ 
    delegate string DoGoodJob(string filename ,bool isAdd);
    delegate string DoGoodJob2(ParameterObject _po);

    class ParallelHelper
    {
       public  static int GetWorkThreadCount()
        {
            int workThreadCount = Environment.ProcessorCount;
            if (!Util.GetAppSetting("ParallelDegree").Equals("0"))
            {
                workThreadCount =
                    int.TryParse(Util.GetAppSetting("ParallelDegree"), out workThreadCount)
                    ? workThreadCount :
                    Environment.ProcessorCount;
            }
            return workThreadCount;
        }

        static string DoWork(ManualResetEvent mre, string filename,bool isAdd,DoGoodJob f)
        {
            string rst;
            rst =f(filename, isAdd);
            mre.Set();
            return rst;
        }

        static string DoWork2(ManualResetEvent mre,ParameterObject _po, DoGoodJob2 f)
        {
            string rst;
            rst = f(_po);
            mre.Set();
            return rst;
        }

        static public void ParallelDoJob(string[] filenames,bool isAdd,RichTextBox _rtbMsg, DoGoodJob f)
        {
            Action<string> cb = v =>
            {
                _rtbMsg.AppendText(v + Environment.NewLine);
            };
            Func<RichTextBox,string> db =r=> { return _rtbMsg.Text; };

            _rtbMsg.BeginInvoke(cb, "System start to work,please wait for a moment......\r\n");
            
            int workThreadCount = GetWorkThreadCount();

            Dictionary<string, int> dict = new Dictionary<string, int>();
            DateTime st = DateTime.Now;
            Queue<string> _queue = new Queue<string>(filenames);
            List<ManualResetEvent> _listmre = new List<ManualResetEvent>();
            string pkgpath = string.Empty;
            for (int i = 0; i < workThreadCount; i++)
            {
                Thread th = new Thread
                (
                    obj =>
                    {
                        while (true)
                        {
                            lock (((ICollection)_queue).SyncRoot)
                            {
                                if (_queue.Count == 0) { break; }
                                pkgpath = _queue.Dequeue();
                                _listmre.Add(new ManualResetEvent(false));
                            }
                            _rtbMsg.BeginInvoke(cb, DoWork(_listmre[_listmre.Count - 1], pkgpath, isAdd, f));
                            if (dict.ContainsKey(Thread.CurrentThread.Name)) dict[Thread.CurrentThread.Name]++;
                            else dict.Add(Thread.CurrentThread.Name, 1);
                        }
                    }
                );
                th.Name = "WorkThread" + i.ToString();
                th.Start();
            }
            _listmre.ForEach(item => item.WaitOne());
            
             _rtbMsg.BeginInvoke(cb, "Total File count:" + filenames.Length + Environment.NewLine);
            string strmsg = "All files are finished, cusum time: " + (DateTime.Now - st).TotalSeconds + " seconds";
            _rtbMsg.BeginInvoke(cb, strmsg + Environment.NewLine);

            List<string> processinfolist = new List<string>(
                _rtbMsg.EndInvoke( _rtbMsg.BeginInvoke(db,_rtbMsg)).ToString()
                .Split("\r\n".ToCharArray()));
            if (_rtbMsg.EndInvoke(_rtbMsg.BeginInvoke(db, _rtbMsg)).ToString().IndexOf("EXITCODE:1") > -1)
                _rtbMsg.BeginInvoke(cb, "Error files list:" + Environment.NewLine);
            processinfolist.ForEach(item =>
            {
                if (item.StartsWith("EXITCODE:1"))
                {
                    pkgpath =item.Substring(item.IndexOf("Package:") + 8);
                    _rtbMsg.BeginInvoke(cb,pkgpath + Environment.NewLine);
                }
            }
            );
            _rtbMsg.BeginInvoke(cb, "*********************************************************$\r\n");
            foreach (var item in dict)
            {
                _rtbMsg.BeginInvoke(cb,item.Key + ":" + item.Value.ToString()+"\r\n");
            }
                MessageBox.Show("done!");
        }

        static public void ParallelDoJob(ParameterObject _po, DoGoodJob2 f)
        {
            RichTextBox _rtbMsg = _po._rtb;
            string[] filenames = _po._fileNames;

            Action<string> cb = v =>
            {
                _rtbMsg.AppendText(v + Environment.NewLine);
            };
            Func<RichTextBox, string> db = r => { return _rtbMsg.Text; };

            _rtbMsg.BeginInvoke(cb, "System start to work,please wait for a moment......\r\n");

            int workThreadCount = GetWorkThreadCount();
             
            Dictionary<string, int> dict = new Dictionary<string, int>();//Used for Thread record
            DateTime st = DateTime.Now;
            Queue<string> _queue = new Queue<string>(filenames);
            List<ManualResetEvent> _listmre = new List<ManualResetEvent>();
            string pkgpath = string.Empty;
            for (int i = 0; i < workThreadCount; i++)
            {
                Thread th = new Thread
                (
                    obj =>
                    {
                        while (true)
                        {
                            lock (((ICollection)_queue).SyncRoot)
                            {
                                if (_queue.Count == 0) { break; }
                                pkgpath = _queue.Dequeue();
                                _listmre.Add(new ManualResetEvent(false));
                            }
                            _rtbMsg.BeginInvoke(cb, DoWork2(_listmre[_listmre.Count - 1],
                                new ParameterObject() { 
                                _fileName= pkgpath,_isAdd=_po._isAdd,
                                _varNameValue=_po._varNameValue
                                }, f));
                            if (dict.ContainsKey(Thread.CurrentThread.Name)) dict[Thread.CurrentThread.Name]++;
                            else dict.Add(Thread.CurrentThread.Name, 1);
                        }
                    }
                );
                th.Name = "WorkThread" + i.ToString();
                th.Start();
            }
            _listmre.ForEach(item => item.WaitOne());

            _rtbMsg.BeginInvoke(cb, "Total File count:" + filenames.Length + Environment.NewLine);
            string strmsg = "All files are finished, cusum time: " + (DateTime.Now - st).TotalSeconds + " seconds";
            _rtbMsg.BeginInvoke(cb, strmsg + Environment.NewLine);

            List<string> processinfolist = new List<string>(
                _rtbMsg.EndInvoke(_rtbMsg.BeginInvoke(db, _rtbMsg)).ToString()
                .Split("\r\n".ToCharArray()));
            if (_rtbMsg.EndInvoke(_rtbMsg.BeginInvoke(db, _rtbMsg)).ToString().IndexOf("EXITCODE:1") > -1)
                _rtbMsg.BeginInvoke(cb, "Error files list:" + Environment.NewLine);
            processinfolist.ForEach(item =>
            {
                if (item.StartsWith("EXITCODE:1"))
                {
                    pkgpath = item.Substring(item.IndexOf("Package:") + 8);
                    _rtbMsg.BeginInvoke(cb, pkgpath + Environment.NewLine);
                }
            }
            );
            _rtbMsg.BeginInvoke(cb, "*********************************************************$\r\n");
            foreach (var item in dict)
            {
                _rtbMsg.BeginInvoke(cb, item.Key + ":" + item.Value.ToString() + "\r\n");
            }
            MessageBox.Show("done!");
        }

        static public long FileRowCount(string filename)
        {
            long count = 0;
            
            using (System.IO.StreamReader sr = new System.IO.StreamReader(filename, true))
            {
                long fileLength = sr.BaseStream.Length;
                long remainning = fileLength;
                int bufferlen = (int)(fileLength / 4 + 1);
                char[] filebuffer = new char[bufferlen];
                while (remainning > 0)
                {
                    sr.ReadBlock(filebuffer, 0, bufferlen);

                }
            }
            return count;
        }

        static int FileBlockRowCount(char[] fileblock)
        {
            int count = 0;
            foreach (char b in fileblock)
            {
                if (b == '\n')
                {
                    count++;
                }
            }
            return count;
        }
    }

    
}
